<template>
  <el-dialog
    v-model="visible"
    draggable
    :title="title || ''"
    class="material-selector-dialog"
    :append-to-body="true"
    :close-on-click-modal="false"
    :width="dialogWidth"
    @close="handleClose"
  >
    <!-- 公共/私有切换 -->
    <div class="dialog-header">
      <el-radio-group
        v-model="sessionType"
        class="tab-group"
        @change="handleSessionTypeChange"
      >
        <el-radio value="private" border>{{ t("private") }}</el-radio>
        <el-radio value="public" border>{{ t("public") }}</el-radio>
      </el-radio-group>
    </div>

    <!-- 搜索栏 -->
    <div class="search-bar">
      <el-input
        v-model="searchText"
        :placeholder="t('enterSearchContent')"
        class="search-input"
        clearable
      >
        <template #append>
          <el-button :icon="Search" @click="handleSearch" />
        </template>
      </el-input>
      <div class="action-buttons">
        <el-button :icon="Plus" type="primary" @click="handleAdd">
          {{ t("add") }}
        </el-button>
        <el-button v-if="isInFolderDetail" @click="exitFolderDetail">
          {{ t("back") }}
        </el-button>
      </div>
    </div>

    <!-- 素材类型标签页 -->
    <el-tabs
      v-model="activeMaterialType"
      class="material-tabs"
      @tab-click="handleTabClick"
    >
      <el-tab-pane
        v-for="tab in displayedTabs"
        :key="tab.type"
        :label="tab.label"
        :name="tab.type"
      >
        <div v-loading="loading">
          <!-- 文件夹列表 -->
          <div v-if="!isInFolderDetail" class="folder-container">
            <div
              v-for="folder in folders"
              :key="folder.id"
              class="folder-item"
              @mouseenter="folder.showActions = true"
              @mouseleave="folder.showActions = false"
              @click="enterFolderDetail(folder)"
            >
              <el-icon :size="48"><Folder /></el-icon>
              <span class="folder-name">{{ folder.name }}</span>
              <div v-show="folder.showActions" class="folder-actions">
                <el-button
                  link
                  size="small"
                  @click.stop="handleFolderAction(folder, 'edit')"
                >
                  {{ t("edit") }}
                </el-button>
                <el-button
                  link
                  size="small"
                  @click.stop="handleFolderAction(folder, 'delete')"
                >
                  {{ t("delete") }}
                </el-button>
              </div>
            </div>
          </div>

          <!-- 素材列表 -->
          <div v-else class="material-container">
            <input
              :ref="(el) => (fileInputRefs[tab.type] = el as HTMLInputElement)"
              type="file"
              :accept="tab.accept"
              style="display: none"
              multiple
              @change="handleFileUpload"
            />
            <div v-if="currentFolder" class="material-grid">
              <div
                v-for="(item, index) in currentFolder.items"
                :key="index"
                class="material-item"
                @mouseenter="item.showActions = true"
                @mouseleave="item.showActions = false"
              >
                <!-- 素材预览 -->
                <div class="material-preview">
                  <slot
                    name="material-preview"
                    :item="item"
                    :type="activeMaterialType"
                  >
                    <component
                      :is="getPreviewComponent(activeMaterialType)"
                      v-if="getPreviewComponent(activeMaterialType)"
                      :item="item"
                      :material-type="activeMaterialType"
                    />
                  </slot>
                </div>

                <!-- 操作按钮 -->
                <div v-show="item.showActions" class="material-actions">
                  <el-button
                    link
                    size="small"
                    @click="handleMaterialAction(item, 'edit')"
                  >
                    {{ t("edit") }}
                  </el-button>
                  <el-button
                    link
                    size="small"
                    @click="handleMaterialAction(item, 'delete')"
                  >
                    {{ t("delete") }}
                  </el-button>
                  <el-button
                    link
                    size="small"
                    type="primary"
                    @click="handleMaterialAction(item, 'use')"
                  >
                    {{ t("use") }}
                  </el-button>
                </div>
              </div>
            </div>
          </div>
        </div>
      </el-tab-pane>
    </el-tabs>

    <!-- 对话框缩放手柄 -->
    <div class="dialog-resize-handle" @mousedown="handleDialogResizeStart">
      <el-icon><TopLeft /></el-icon>
      <el-icon><BottomRight /></el-icon>
    </div>
  </el-dialog>
</template>

<script setup lang="ts">
import { ref, computed, watch, nextTick } from "vue";
import { ElMessage, ElMessageBox, type TabsPaneContext } from "element-plus";
import {
  Search,
  Plus,
  Folder as FolderIcon,
  TopLeft,
  BottomRight,
} from "@element-plus/icons-vue";
import type {
  MaterialSelectorProps,
  MaterialItem,
  FolderItem,
  MaterialTab,
  MaterialAPI,
} from "./types";

const props = withDefaults(defineProps<MaterialSelectorProps>(), {
  visible: false,
  title: "",
  dialogWidth: "800px",
  uploadLimit: 9,
  maxFileSize: 10 * 1024 * 1024, // 10MB
  enablePublicPrivate: true,
});

const emit = defineEmits<{
  "update:visible": [value: boolean];
  select: [item: MaterialItem];
  close: [];
}>();

// 响应式状态
const visible = ref(props.visible);
const sessionType = ref<"private" | "public">("private");
const searchText = ref("");
const activeMaterialType = ref("");
const loading = ref(false);
const isInFolderDetail = ref(false);
const currentFolder = ref<FolderItem | null>(null);
const folders = ref<FolderItem[]>([]);
const fileInputRefs = ref<Record<string, HTMLInputElement>>({});

// 计算属性
const isPublic = computed(() => sessionType.value === "public");

const displayedTabs = computed(() => {
  return props.tabs.filter((tab) => tab.display !== false);
});

// 监听 props.visible 变化
watch(
  () => props.visible,
  (newValue) => {
    visible.value = newValue;
    if (newValue && displayedTabs.value.length > 0) {
      activeMaterialType.value = displayedTabs.value[0].type;
      handleSessionTypeChange(sessionType.value);
    }
  }
);

// 监听内部 visible 变化
watch(visible, (newValue) => {
  emit("update:visible", newValue);
  if (!newValue) {
    emit("close");
  }
});

// 国际化
const t = (key: string) => {
  return props.t?.(key) || key;
};

// 会话类型切换
const handleSessionTypeChange = (type: "private" | "public") => {
  sessionType.value = type;
  exitFolderDetail();
  fetchFolderData();
};

// 搜索
const handleSearch = () => {
  if (isInFolderDetail.value) {
    fetchMaterialData(searchText.value);
  } else {
    fetchFolderData(searchText.value);
  }
};

// 标签页点击
const handleTabClick = async (pane: TabsPaneContext) => {
  exitFolderDetail();
  const tabName = pane.props.name;
  if (tabName) {
    activeMaterialType.value = tabName.toString();
    await fetchFolderData();
  }
};

// 进入文件夹详情
const enterFolderDetail = async (folder: FolderItem) => {
  isInFolderDetail.value = true;
  currentFolder.value = folder;
  await fetchMaterialData();
};

// 退出文件夹详情
const exitFolderDetail = () => {
  isInFolderDetail.value = false;
  currentFolder.value = null;
};

// 获取文件夹列表
const fetchFolderData = async (name?: string) => {
  if (!props.api) return;

  loading.value = true;
  try {
    const result = await props.api.listMaterialGroup({
      page: 1,
      pageSize: 300,
      isPublic: isPublic.value,
      type: activeMaterialType.value,
      name: name,
      useTypes: [1],
    });

    folders.value = (result.materialGroups || []).map((item: any) => ({
      id: item.id,
      name: item.name,
      showActions: false,
      items: [],
    }));
  } catch (error) {
    console.error("获取文件夹列表失败:", error);
    folders.value = [];
  } finally {
    loading.value = false;
  }
};

// 获取素材列表
const fetchMaterialData = async (name?: string) => {
  if (!props.api || !currentFolder.value) return;

  loading.value = true;
  try {
    const result = await props.api.listMaterial({
      groupId: currentFolder.value.id,
      page: 1,
      pageSize: 500,
      name: name,
      useTypes: [1],
    });

    if (currentFolder.value) {
      currentFolder.value.items = (result.materials || []).map((item: any) => ({
        id: item.id,
        content: item.content,
        showActions: false,
        name: item.name,
        remark: item.remark,
        fileKey: item.fileKey,
        type: item.type,
      }));
    }
  } catch (error) {
    console.error("获取素材列表失败:", error);
  } finally {
    loading.value = false;
  }
};

// 文件夹操作
const handleFolderAction = async (folder: FolderItem, action: string) => {
  if (!props.api) return;

  switch (action) {
    case "edit":
      await handleEditFolder(folder);
      break;
    case "delete":
      await handleDeleteFolder(folder);
      break;
  }
};

// 新增文件夹
const addFolder = async () => {
  if (!props.api) return;

  try {
    const { value } = await ElMessageBox.prompt("", t("createFolder"), {
      inputPattern: /^[^/\\]+$/,
      inputErrorMessage: t("folderNameNotEmpty"),
      confirmButtonText: t("confirm"),
      cancelButtonText: t("cancel"),
    });

    await props.api.createMaterialGroup({
      name: value,
      type: activeMaterialType.value,
      isPublic: isPublic.value,
      useType: 1,
    });

    await fetchFolderData();
    ElMessage.success(t("operationSuccess"));
  } catch (error) {
    // 用户取消操作
  }
};

// 编辑文件夹
const handleEditFolder = async (folder: FolderItem) => {
  if (!props.api) return;

  try {
    const { value } = await ElMessageBox.prompt("", t("updateFolderName"), {
      inputPattern: /^[^/\\]+$/,
      inputErrorMessage: t("folderNameNotEmpty"),
      confirmButtonText: t("confirm"),
      cancelButtonText: t("cancel"),
      inputValue: folder.name,
    });

    if (value) {
      await props.api.updateMaterialGroup({
        id: folder.id,
        name: value,
        isPublic: isPublic.value,
      });

      folder.name = value;
      ElMessage.success(t("operationSuccess"));
    }
  } catch (error) {
    // 用户取消操作
  }
};

// 删除文件夹
const handleDeleteFolder = async (folder: FolderItem) => {
  if (!props.api) return;

  try {
    await ElMessageBox.confirm(t("confirmDeleteFolder"), t("warning"), {
      confirmButtonText: t("confirm"),
      cancelButtonText: t("cancel"),
      type: "warning",
    });

    await props.api.deleteMaterialGroup({ id: folder.id });

    const index = folders.value.findIndex((f) => f.id === folder.id);
    if (index !== -1) {
      folders.value.splice(index, 1);
    }

    exitFolderDetail();
    ElMessage.success(t("operationSuccess"));
  } catch (error) {
    // 用户取消操作
  }
};

// 素材操作
const handleMaterialAction = async (item: MaterialItem, action: string) => {
  switch (action) {
    case "edit":
      await handleEditMaterial(item);
      break;
    case "delete":
      await handleDeleteMaterial(item);
      break;
    case "use":
      handleUseMaterial(item);
      break;
  }
};

// 编辑素材
const handleEditMaterial = async (item: MaterialItem) => {
  if (!props.api) return;

  try {
    const isText = activeMaterialType.value === "TEXT";
    const { value } = await ElMessageBox.prompt(
      "",
      isText ? t("updateText") : t("updateFileName"),
      {
        inputPattern: /^[^/\\]+$/,
        inputErrorMessage: isText ? t("textNotEmpty") : t("fileNameNotEmpty"),
        confirmButtonText: t("confirm"),
        cancelButtonText: t("cancel"),
        inputValue: isText ? item.content : item.remark,
        inputType: isText ? "textarea" : "text",
      }
    );

    if (value) {
      const updateData: any = { id: item.id };
      if (isText) {
        updateData.content = value;
        item.content = value;
      } else {
        updateData.remark = value;
        item.remark = value;
      }

      await props.api.updateMaterial(updateData);
      ElMessage.success(t("operationSuccess"));
    }
  } catch (error) {
    // 用户取消操作
  }
};

// 删除素材
const handleDeleteMaterial = async (item: MaterialItem) => {
  if (!props.api || !currentFolder.value) return;

  try {
    await ElMessageBox.confirm(t("confirmDeleteMaterial"), t("warning"), {
      confirmButtonText: t("confirm"),
      cancelButtonText: t("cancel"),
      type: "warning",
    });

    await props.api.batchDeleteMaterial({ ids: [item.id] });

    const index = currentFolder.value.items.findIndex((m) => m.id === item.id);
    if (index !== -1) {
      currentFolder.value.items.splice(index, 1);
    }

    ElMessage.success(t("operationSuccess"));
  } catch (error) {
    // 用户取消操作
  }
};

// 使用素材
const handleUseMaterial = (item: MaterialItem) => {
  emit("select", item);
  visible.value = false;
};

// 文件上传
const handleFileUpload = async (event: Event) => {
  const target = event.target as HTMLInputElement;
  const files = target.files;

  if (!files || !props.uploadHandler) {
    return;
  }

  // 检查文件数量
  if (files.length > props.uploadLimit) {
    ElMessage.error(
      t("maxFileLimitError").replace("{number}", String(props.uploadLimit))
    );
    target.value = "";
    return;
  }

  // 检查文件大小
  for (let i = 0; i < files.length; i++) {
    const file = files[i];
    if (file.size > props.maxFileSize) {
      ElMessage.error(t("fileSizeLimitError").replace("{fileName}", file.name));
      target.value = "";
      return;
    }
  }

  // 上传文件
  for (let i = 0; i < files.length; i++) {
    const file = files[i];
    try {
      const result = await props.uploadHandler(file);
      await addMaterial(result.url, file.name, result.key);
    } catch (error) {
      console.error("上传文件失败:", error);
      ElMessage.error(t("uploadFailed"));
    }
  }

  target.value = "";
};

// 添加素材
const addMaterial = async (
  contentOrUrl: string,
  name: string,
  fileKey: string = ""
) => {
  if (!props.api || !currentFolder.value) return;

  try {
    await props.api.createMaterial({
      name: name,
      content: fileKey || contentOrUrl,
      groupId: currentFolder.value.id,
      type: activeMaterialType.value,
      useType: 1,
    });

    // 刷新素材列表
    await fetchMaterialData();
    ElMessage.success(t("operationSuccess"));
  } catch (error) {
    console.error("添加素材失败:", error);
  }
};

// 添加按钮处理
const handleAdd = () => {
  if (isInFolderDetail.value) {
    // 打开文件选择器
    const input = fileInputRefs.value[activeMaterialType.value];
    if (input) {
      input.click();
    }
  } else {
    // 添加文件夹
    addFolder();
  }
};

// 获取预览组件
const getPreviewComponent = (type: string) => {
  // 这里可以根据类型返回不同的预览组件
  // 默认使用插槽
  return null;
};

// 对话框关闭
const handleClose = () => {
  visible.value = false;
};

// 对话框缩放
let initialWidth = 0;
let initialHeight = 0;
let startClientX = 0;
let startClientY = 0;

const handleDialogResizeStart = (e: MouseEvent) => {
  e.preventDefault();
  startClientX = e.clientX;
  startClientY = e.clientY;

  const dialog = document.querySelector(
    ".material-selector-dialog .el-dialog"
  ) as HTMLElement;
  if (dialog) {
    initialWidth = parseInt(window.getComputedStyle(dialog).width, 10);
    initialHeight = parseInt(window.getComputedStyle(dialog).height, 10);

    document.addEventListener("mousemove", handleDialogResizeMove);
    document.addEventListener("mouseup", handleDialogResizeEnd);
  }
};

const handleDialogResizeMove = (e: MouseEvent) => {
  const width = initialWidth + (e.clientX - startClientX);
  const height = initialHeight + (e.clientY - startClientY);
  const dialog = document.querySelector(
    ".material-selector-dialog .el-dialog"
  ) as HTMLElement;
  if (dialog) {
    dialog.style.width = `${Math.max(width, 600)}px`;
    dialog.style.height = `${Math.max(height, 400)}px`;
  }
};

const handleDialogResizeEnd = () => {
  document.removeEventListener("mousemove", handleDialogResizeMove);
  document.removeEventListener("mouseup", handleDialogResizeEnd);
};
</script>

<style scoped lang="scss">
.material-selector-dialog {
  :deep(.el-dialog) {
    min-width: 600px;
    min-height: 400px;
  }
}

.dialog-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 0;
  margin-bottom: 16px;
  border-bottom: 1px solid #ebeef5;

  .tab-group {
    margin: 0;
  }
}

.search-bar {
  display: flex;
  gap: 12px;
  margin-bottom: 16px;

  .search-input {
    flex: 1;
  }

  .action-buttons {
    display: flex;
    gap: 8px;
  }
}

.material-tabs {
  min-height: 300px;

  :deep(.el-tabs__content) {
    max-height: 450px;
    overflow-y: auto;
  }
}

.folder-container {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  padding: 16px;

  .folder-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    width: 100px;
    padding: 12px;
    cursor: pointer;
    border-radius: 8px;
    transition: all 0.3s;

    &:hover {
      background-color: #f5f7fa;
    }

    .folder-name {
      font-size: 14px;
      text-align: center;
      word-break: break-all;
    }

    .folder-actions {
      display: flex;
      gap: 8px;
      margin-top: 4px;
    }
  }
}

.material-container {
  padding: 16px;
}

.material-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;

  .material-item {
    position: relative;
    cursor: pointer;
    border-radius: 8px;
    transition: all 0.3s;

    &:hover {
      box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
    }

    .material-preview {
      min-width: 110px;
      max-width: 210px;
    }

    .material-actions {
      display: flex;
      justify-content: center;
      gap: 8px;
      padding: 8px;
      background-color: rgba(255, 255, 255, 0.9);
      border-top: 1px solid #ebeef5;
    }
  }
}

.dialog-resize-handle {
  position: absolute;
  right: 0;
  bottom: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  cursor: se-resize;
  background-color: #f5f7fa;
  border-radius: 4px 0 0 0;

  .el-icon {
    font-size: 14px;
    color: #909399;
  }
}
</style>
